'=====================================================================
'
'  File:    StoreSurvey.vb for Store Survey XML Example
'  Summary: Winform for displaying a product catalog stored in
'			the AdventureWorks OLTP database.
'  Date:    January 20, 2006
'
'---------------------------------------------------------------------
'  This file is part of the Microsoft SQL Server Code Samples.
'  Copyright (C) Microsoft Corporation.  All rights reserved.
'
'  This source code is intended only as a supplement to Microsoft
'  Development Tools and/or on-line documentation.  See these other
'  materials for detailed information regarding Microsoft code samples.
'
'  THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
'  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
'  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
'  PARTICULAR PURPOSE.
'======================================================= 

Imports System
Imports System.Windows.Forms
Imports System.IO
Imports System.Xml
Imports System.Net
Imports System.Net.Cache
Imports System.Globalization
Imports System.ComponentModel

Partial Public Class StoreSurvey 'The Partial modifier is only required on one class definition per project.
    Inherits Form
    ' How much space to preallocate for the XML document as we construct it
    ' before it is transmitted to the server's web service.
    Private Const ExpectedDocSize As Integer = 2048

    Private BusinessCategories() As ComboItem = _
        {New ComboItem(), _
        New ComboItem("BM", "Bicycle Manufacturer"), _
        New ComboItem("BS", "Bicycle Store"), _
        New ComboItem("OS", "Online Store"), _
        New ComboItem("SGS", "Sporting Goods Store"), _
        New ComboItem("D", "Discount Store")}

    Private SpecialtyCategories() As ComboItem = _
        {New ComboItem(), _
        New ComboItem("Family", "Family Oriented"), _
        New ComboItem("Kids", "Kids Bikes"), _
        New ComboItem("Road", "Road Racing Bikes"), _
        New ComboItem("BMX", "BMX Racing"), _
        New ComboItem("Mountain", "Mountain Biking"), _
        New ComboItem("All", "All types")}

    Private BrandCategories() As ComboItem = _
        {New ComboItem(), _
        New ComboItem("AW", "Exclusively Adventure-Works"), _
        New ComboItem("2", "One other brand"), _
        New ComboItem("3", "Two other brands"), _
        New ComboItem("4+", "More than three brands")}

    Private InternetConnectionCategories() As ComboItem = _
        {New ComboItem(), _
        New ComboItem("56kb", "56kb dial up"), _
        New ComboItem("ISDN", "ISDN"), _
        New ComboItem("DSL", "DSL or Cable Modem"), _
        New ComboItem("T1", "T1"), _
        New ComboItem("T2", "T2"), _
        New ComboItem("T3", "T3")}

    Public Sub New()
        InitializeComponent()

        BusinessTypeComboBox.Items.AddRange(BusinessCategories)
        SpecialtyComboBox.Items.AddRange(SpecialtyCategories)
        BrandsComboBox.Items.AddRange(BrandCategories)
        InternetConnectionComboBox.Items.AddRange(InternetConnectionCategories)
    End Sub

    Private Shared Function GetSoapRequestXml(ByVal survey As String) As String
        Return _
            "<soap:Envelope xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'>" _
            & "  <soap:Body>" _
            & "    <SaveStoreSurvey xmlns='testns'>" _
            & "        <SID>1</SID> " _
            & "        <Survey> " _
            & survey _
            & "	     </Survey>" _
            & "    </SaveStoreSurvey>" _
            & "  </soap:Body>" _
            & "</soap:Envelope>"
    End Function

    Private Sub PostSoapRequest(ByVal requestXml As String)
        Try
            Dim soapWebRequest As HttpWebRequest = CType(WebRequest.Create("http://localhost/StoreSurvey/"), HttpWebRequest)
            soapWebRequest.Accept = "text/xml"
            soapWebRequest.ContentType = "text/xml"
            soapWebRequest.CachePolicy = New RequestCachePolicy(RequestCacheLevel.NoCacheNoStore)
            soapWebRequest.Headers.Add("SOAPAction", String.Empty)
            soapWebRequest.Credentials = CredentialCache.DefaultCredentials
            soapWebRequest.Method = "POST"

            Dim webStream As Stream = soapWebRequest.GetRequestStream()

            Dim webWriter As StreamWriter = Nothing
            Try
                webWriter = New StreamWriter(webStream)
                webWriter.Write(requestXml)
                webWriter.Flush()
            Finally
                If webWriter IsNot Nothing Then webWriter.Close()
            End Try

            Dim response As WebResponse = soapWebRequest.GetResponse()
            Using rs As Stream = response.GetResponseStream()
                Using sr As New StreamReader(rs)
                    sr.ReadToEnd()
                End Using
            End Using

            InformationLabel.Text = My.Resources.DataSaved

        Catch e As System.Net.WebException
            Dim wr As WebResponse = e.Response
            If wr Is Nothing Then
                InformationLabel.Text = My.Resources.ErrorCondition + e.ToString()
            Else
                Using rs As Stream = wr.GetResponseStream()
                    Using sr As New StreamReader(rs)
                        InformationLabel.Text = My.Resources.ErrorCondition + e.ToString() + sr.ReadToEnd()
                    End Using
                End Using
            End If
        End Try
    End Sub


    Private Sub exitMenuItem_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles exitMenuItem.Click
        Application.Exit()
    End Sub

    Private Sub saveMenuItem_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles saveMenuItem.Click
        Dim control As Control
        For Each control In Controls
            ' Set focus on control
            control.Focus()

            ' Validate causes the control's Validating event to be fired,
            ' if CausesValidation is True
            If Not Validate() Then
                InformationLabel.Text = My.Resources.CorrectMistakes
                Return
            End If
        Next

        Using sw As New StringWriter(CultureInfo.InvariantCulture)
            Using xmlw As New XmlTextWriter(sw)
                xmlw.WriteStartElement("StoreSurvey", "http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/StoreSurvey")
                ' SelectedValue member not currently working, so we need to use SelectedItem member
                ' on combo boxes temporarily.
                MaybeWriteXmlElement("AnnualSales", MaybeParseDecimal(AnnualSalesTextBox.Text), xmlw, True)
                MaybeWriteXmlElement("AnnualRevenue", MaybeParseDecimal(AnnualRevenueTextBox.Text), xmlw, True)
                MaybeWriteXmlElement("BankName", BankNameTextBox.Text, xmlw)
                MaybeWriteXmlElement("BusinessType", BusinessTypeComboBox.SelectedItem, xmlw)
                MaybeWriteXmlElement("YearOpened", YearOpenedTextBox.Text, xmlw)
                MaybeWriteXmlElement("Specialty", SpecialtyComboBox.SelectedItem, xmlw)
                MaybeWriteXmlElement("SquareFeet", MaybeParseDecimal(StoreSizeTextBox.Text), xmlw, True)
                MaybeWriteXmlElement("Brands", BrandsComboBox.SelectedItem, xmlw)
                MaybeWriteXmlElement("Internet", InternetConnectionComboBox.SelectedItem, xmlw)
                MaybeWriteXmlElement("Comments", CommentsTextBox.Text, xmlw)
                xmlw.WriteEndElement()

                xmlw.Flush()
            End Using

            Dim requestString As String = GetSoapRequestXml(sw.ToString())
            PostSoapRequest(requestString)
        End Using
    End Sub

    Private Shared Function MaybeParseDecimal(ByVal val As String) As String
        If val.Length = 0 Then
            Return String.Empty
        Else
            Return Decimal.Parse(val, CultureInfo.InvariantCulture).ToString(CultureInfo.CurrentUICulture)
        End If
    End Function

    Private Overloads Shared Sub MaybeWriteXmlElement(ByVal elementName As String, ByVal elementValue As Object, ByVal xmlWriter As XmlTextWriter)
        MaybeWriteXmlElement(elementName, elementValue, xmlWriter, False)
    End Sub

    Private Overloads Shared Sub MaybeWriteXmlElement(ByVal elementName As String, ByVal elementValue As Object, ByVal xmlWriter As XmlTextWriter, ByVal isDecimal As Boolean)
        Dim elementItem As ComboItem
        Dim element As String

        If Not (elementValue Is Nothing) Then
            ' SelectedValue member not currently working, so we need to use SelectedItem member
            ' on combo boxes temporarily.
            elementItem = TryCast(elementValue, ComboItem)

            If (elementItem IsNot Nothing) Then
                elementValue = elementItem.KeyName
            End If

            element = CStr(elementValue)
            If element.Length > 0 Then
                If isDecimal Then
                    'We use the en-US culture because that is how the XML Schema specification 
                    '(http://www.w3.org/TR/xmlschema-2/#decimal) defines the decimal data type.
                    element = Decimal.Parse(element, CultureInfo.CurrentCulture).ToString(CultureInfo.CreateSpecificCulture("en-US"))
                End If
                xmlWriter.WriteElementString(elementName, "http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/StoreSurvey", element)
            End If
        End If
    End Sub

    Private Sub YearOpenedTextBox_Validating(ByVal sender As Object, ByVal e As CancelEventArgs) Handles YearOpenedTextBox.Validating
        surveyErrorProvider.SetError(YearOpenedTextBox, ValidateElement("Year opened", YearOpenedTextBox.Text, 1500D, System.Convert.ToDecimal(DateTime.Now.Year + 1), True, e))
    End Sub

    Private Sub StoreSizeTextBox_Validating(ByVal sender As Object, ByVal e As CancelEventArgs) Handles StoreSizeTextBox.Validating
        surveyErrorProvider.SetError(StoreSizeTextBox, ValidateElement("Store size", StoreSizeTextBox.Text, 50D, 50000D, False, e))
    End Sub

    Private Sub AnnualSalesTextBox_Validating(ByVal sender As Object, ByVal e As CancelEventArgs) Handles AnnualSalesTextBox.Validating
        surveyErrorProvider.SetError(AnnualSalesTextBox, ValidateElement("Annual sales", AnnualSalesTextBox.Text, 0D, 900000000000D, False, e))
    End Sub

    Private Sub AnnualRevenueTextBox_Validating(ByVal sender As Object, ByVal e As CancelEventArgs) Handles AnnualRevenueTextBox.Validating
        surveyErrorProvider.SetError(AnnualRevenueTextBox, ValidateElement("Annual revenue", AnnualRevenueTextBox.Text, 0D, 900000000000D, False, e))
    End Sub

    Private Sub YearOpenedTextBox_Validated(ByVal sender As Object, ByVal e As System.EventArgs) Handles YearOpenedTextBox.Validated
        surveyErrorProvider.SetError(YearOpenedTextBox, String.Empty)
    End Sub

    Private Sub StoreSizeTextBox_Validated(ByVal sender As Object, ByVal e As System.EventArgs) Handles StoreSizeTextBox.Validated
        surveyErrorProvider.SetError(StoreSizeTextBox, String.Empty)
    End Sub

    Private Sub AnnualSalesTextBox_Validated(ByVal sender As Object, ByVal e As System.EventArgs) Handles AnnualSalesTextBox.Validated
        surveyErrorProvider.SetError(AnnualSalesTextBox, String.Empty)
    End Sub

    Private Sub AnnualRevenueTextBox_Validated(ByVal sender As Object, ByVal e As System.EventArgs) Handles AnnualRevenueTextBox.Validated
        surveyErrorProvider.SetError(AnnualRevenueTextBox, String.Empty)
    End Sub

    <System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")> _
    Private Shared Function ValidateElement(ByVal elementName As String, ByVal elementValue As Object, ByVal min As Object, ByVal max As Object, ByVal mustBeInt As Boolean, ByVal e As CancelEventArgs) As String
        Dim errorString As String = String.Empty

        Try
            If Not (elementValue Is Nothing) AndAlso CStr(elementValue).Length > 0 Then
                Dim stringValue As String = CStr(elementValue)
                Dim i As Integer = 0
                Do
                    If Not Char.IsDigit(stringValue(i)) Then
                        If mustBeInt Then
                            Throw New FormatException(My.Resources.EnterInteger)
                        Else
                            If stringValue.Substring(i).StartsWith(CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalSeparator) Then
                                'If we're parsing a decimal value, allow decimals, and if
                                'a decimal is more than one character in this culture, skip
                                'over all of the characters except the last one, as 
                                'we'll cover the last character at the end of this loop.
                                i += CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalSeparator.Length - 1
                            ElseIf stringValue.Substring(i).StartsWith(CultureInfo.CurrentCulture.NumberFormat.CurrencyGroupSeparator) Then
                                'If we're parsing a decimal value, allow group separators, and if
                                'a group separator is more than one character in this culture, skip
                                'over all of the characters except the last one, as 
                                'we'll cover the last character at the end of this loop.
                                i += CultureInfo.CurrentCulture.NumberFormat.CurrencyGroupSeparator.Length - 1
                            Else
                                Throw New FormatException(String.Format(CultureInfo.CurrentUICulture, My.Resources.InvalidCharacter, stringValue(i)))
                            End If
                        End If
                    End If

                    i += 1
                Loop While i < stringValue.Length

                Dim val As Decimal = Decimal.Parse(stringValue, CultureInfo.InvariantCulture)

                If Not (min Is Nothing) AndAlso System.Convert.ToDecimal(min, CultureInfo.CurrentUICulture) > val Then
                    errorString = String.Format(CultureInfo.CurrentUICulture, My.Resources.MustBeAtLeast, elementName, min.ToString())
                ElseIf Not (max Is Nothing) AndAlso val >= System.Convert.ToDecimal(max, CultureInfo.CurrentUICulture) Then
                    errorString = String.Format(CultureInfo.CurrentUICulture, My.Resources.MustBeLessThan, elementName, max.ToString())
                End If
            End If

        Catch fe As System.FormatException
            errorString = fe.Message
        Catch ae As System.ArithmeticException
            errorString = ae.Message
        End Try

        If errorString.Length > 0 Then
            e.Cancel = True
        End If

        Return errorString
    End Function
End Class
